﻿using LWH.ByteProtocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ByteProtocolCSharpDemo
{

    class IndefiniteLengthProtocolBuilder : AbstractIndefiniteLengthProtocol
    {
        /// <summary>
        /// 长度属性的值不需要自己设置，直接通过一个包装属性在内部自动计算并缓存
        /// </summary>
        class StringLengthPropertyBuilder : WrapperAbstractProperty
        {
            public StringLengthPropertyBuilder(AbstractProperty wrappedProperty) : base(wrappedProperty)
            {
            }

            /// <summary>
            /// 计算出自身的value为mStringProperty的长度
            /// </summary>
            /// <returns></returns>
            public override byte[] getData()
            {
                var protocolBuilder = getOwnerProperty() as IndefiniteLengthProtocolBuilder;
                int value = protocolBuilder.mStringProperty.getLength();

                return ByteConverter.getBytes(value, ByteConverter.ByteOrder.BIG_ENDIAN);
            }

            public override void setData(byte[] data, int offset, int length)
            {
            }
        }


        StringLengthPropertyBuilder mStringLengthBuilder;

        StringValueProperty mStringProperty;

        /// <summary>
        /// 由于长度不定，不能为协议定义一个固定长度数组，因此对每个Property进行一个缓存包装，数据从缓存中读写
        /// </summary>
        public IndefiniteLengthProtocolBuilder()
        {
            mStringLengthBuilder = new StringLengthPropertyBuilder(mBasicStringLengthProperty);

            /*
             *这里对于长度的定义方式有几种
             * 1、重写CacheProperty的getLength为return mData.Length;，这种方法比较直观；
             * 2、与Protocol一样，使用Int32ValueProperty从XMLLengthPropertyBuilder中获取Value，这时就会调用
             * getData从中计算mXmlProperty的数据长度，这种方法符合协议定义；
             * 3、如下实现，直接将mBasicXmlProperty的长度定义为mXmlProperty.getData().Length，因为
             * mXmlProperty.getData()等价于mData，这种方法需要写的代码最少；
             */
            mBasicStringProperty = new IndefiniteLengthProperty(this, (property) =>
            {
                return mStringProperty.getData().Length;
            });
            mStringProperty = new StringValueProperty(new CacheProperty(mBasicStringProperty));


            addProperty(mHeaderProperty);
            addProperty(mStringLengthBuilder);
            addProperty(mStringProperty);
        }

        /// <summary>
        /// 重写getData，获取属性中的数据组成协议内容
        /// </summary>
        /// <returns></returns>
        public override byte[] getData()
        {
            mData = new byte[getLength()];

            foreach (var property in mPropertyList)
            {
                Buffer.BlockCopy(property.getData(), 0, mData, property.getOffset(), property.getLength());
            }

            return mData;
        }

        public IndefiniteLengthProtocol getProtocol()
        {
            return new IndefiniteLengthProtocol(getData());
        }

        #region Getter&Setter
        public StringValueProperty StringProperty
        {
            get
            {
                return mStringProperty;
            }
        }
        #endregion
    }
}
